package codec;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import packet.*;
import packet.impl.*;
import packet.impl.LoginRequestAbstractPacket;
import packet.impl.LoginResponseAbstractPacket;
import serializer.JSONSerializer;
import serializer.Serializer;

/**
 * @author Admin
 */
public class PacketCodeC {
  public final static PacketCodeC INSTANCE = new PacketCodeC();

  private final static int MAGIC_NUMBER = 0x12345678;

  public ByteBuf encode(AbstractPacket packet) {
    return encode(null, packet);
  }

  public ByteBuf encode(ByteBufAllocator allocator, AbstractPacket packet) {
    // 1、创建 ByteBuf 对象
    ByteBuf byteBuf;
    if (allocator == null) {
      byteBuf = ByteBufAllocator.DEFAULT.ioBuffer();
    } else {
      byteBuf = allocator.ioBuffer();
    }

    // 2、序列化对象
    byte[] bytes = Serializer.DEFAULT.serialize(packet);

    // 3、实际编码过程
    byteBuf.writeInt(MAGIC_NUMBER);
    byteBuf.writeByte(packet.getVersion());
    byteBuf.writeByte(Serializer.JSON_SERIALIZER);
    byteBuf.writeByte(packet.getCommand());
    byteBuf.writeInt(bytes.length);
    byteBuf.writeBytes(bytes);

    return byteBuf;
  }

  public void encode0(ByteBuf byteBuf, AbstractPacket packet) {
    // 1、序列化对象
    byte[] bytes = Serializer.DEFAULT.serialize(packet);

    // 2、实际编码过程
    byteBuf.writeInt(MAGIC_NUMBER);
    byteBuf.writeByte(packet.getVersion());
    byteBuf.writeByte(Serializer.JSON_SERIALIZER);
    byteBuf.writeByte(packet.getCommand());
    byteBuf.writeInt(bytes.length);
    byteBuf.writeBytes(bytes);
  }

  public AbstractPacket decode(ByteBuf byteBuf) {
    // 跳过魔数
    byteBuf.skipBytes(4);

    // 跳过版本号
    byteBuf.skipBytes(1);

    // 序列化算法
    byte serializerAlgorithm = byteBuf.readByte();

    // 指令
    byte command = byteBuf.readByte();

    // 数据长度
    int len = byteBuf.readInt();

    // 数据内容
    byte[] value = new byte[len];
    byteBuf.readBytes(value);

    Class<? extends AbstractPacket> requestType = getRequestType(command);
    Serializer serializer = getSerializer(serializerAlgorithm);

    if (requestType != null && serializer != null) {
      return serializer.deserialize(requestType, value);
    }

    return null;
  }

  private Serializer getSerializer(byte serializerAlgorithm) {
    switch (serializerAlgorithm) {
      case 1:
        return new JSONSerializer();
      default:
        return Serializer.DEFAULT;
    }
  }

  private Class<? extends AbstractPacket> getRequestType(byte command) {
    switch (command) {
      case 1:
        return LoginRequestAbstractPacket.class;
      case 2:
        return LoginResponseAbstractPacket.class;
      case 3:
        return MessageRequestAbstractPacket.class;
      case 4:
        return MessageResponseAbstractPacket.class;
      default:
        return LoginRequestAbstractPacket.class;
    }
  }
}
